package edu.isistan.matching.utils.semanticLexicon;

import iglu.ir.TermVector;

import java.io.File;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Iterator;
import java.util.List;

import org.apache.log4j.Logger;

import edu.mit.jwi.Dictionary;
import edu.mit.jwi.IDictionary;
import edu.mit.jwi.item.IIndexWord;
import edu.mit.jwi.item.ISynset;
import edu.mit.jwi.item.ISynsetID;
import edu.mit.jwi.item.IWord;
import edu.mit.jwi.item.IWordID;
import edu.mit.jwi.item.POS;
import edu.mit.jwi.item.Pointer;

/**
 * Entidad que resuelve la similitud entre dos términos. Para ello, utiliza la
 * base de datos léxica WordNet
 * 
 * @author Matias
 * 
 */
public class WordAnalyzer implements ISemanticLexicon {
	
	public static String SHARED_WNHOME = "/home/mcrasso/library/wordnet";
	
	static Logger logger = Logger.getLogger(WordAnalyzer.class);
	
	
	// Debe ser una propiedad ingresada en el 'Properties'
	String wnhome = null;
		
	IDictionary dictionary = null;

	public WordAnalyzer() {	
		setWnhome(SHARED_WNHOME);
		initialize();
	}
	
	public void initialize() {
		// Por defecto, la carpeta que contiene el diccionario dentro de WordNet se
		// llama 'dict'
		String path = wnhome + File.separator + "dict";
		URL url = null;
		try {
			url = new URL("file", null, path);
		} catch (MalformedURLException e) {			
			logger.error("Error inicializando WordNet", e);
		}
		if (url == null)
			return;

		dictionary = new Dictionary(url);
		dictionary.open();
	}

	public int areHypernyms(String word1, String word2) {

		return findSemanticRelation(word1, word2, 1, Pointer.HYPERNYM);

	}

	public TermVector getHypernyms(String word) {

		return null;
	}

	public int areHyponyms(String word1, String word2) {

		return findSemanticRelation(word1, word2, 1, Pointer.HYPONYM);

	}

	public int findSemanticRelation(String word1, String word2, int prof, Pointer typeSemantic) {
		// Corto la recursión cuando alcanzó el nivel de analisis prefijado
		// como
		// maximo (3 ó 4), aunque el valor por ideal es 2, por temas de
		// performance
		if (prof > MAX_PROF)
			return NO_RELATION;

		IIndexWord idxWord = getDictionary().getIndexWord(word1, POS.NOUN);
		if (idxWord == null) {
			logger.debug("No existe en el diccionario la palabra:" + word1);
			return NO_RELATION;
		}

		List<IWordID> wordsId = idxWord.getWordIDs();

		// Iteramos sobre todas las definiciones de la palabra buscada
		// (wordQuery)
		for (Iterator<IWordID> iterator = wordsId.iterator(); iterator.hasNext();) {

			IWordID wordID = (IWordID) iterator.next();
			// Recuperamos el valor de la palabra a partir de su ID
			IWord word = getDictionary().getWord(wordID);
			ISynset synset = getDictionary().getSynset(word.getSynset().getID());
			List<ISynsetID> hypernyms = synset.getRelatedSynsets(typeSemantic);

			List<IWord> wordsList = null;
			// Por cada conjunto de sinonimos:
			for (ISynsetID sid : hypernyms) {
				wordsList = getDictionary().getSynset(sid).getWords();

				for (Iterator<IWord> i = wordsList.iterator(); i.hasNext();) {

					String lexemaString = i.next().getLemma();

					if (lexemaString.equals(word2)) {
						// Retornamos en nivel que se encontr� la
						// coincidencia.
						return prof;
					} else {
						// Si el valor no coincide, bajo un nivel.
						int moreHypersym = findSemanticRelation(lexemaString, word2, prof + 1, typeSemantic);
						if (moreHypersym > 0) {
							return moreHypersym;
						}
					}

				}
			}
		}

		return NO_RELATION;
	}

	public boolean areSynonyms(String word1, String word2) {
		TermVector sinonimosWord1 = getSynonyms(word1);
		if (sinonimosWord1.get(word2) > 0) {
			return true;
		} else {
			TermVector sinonimosWord2 = getSynonyms(word2);
			if (sinonimosWord2.get(word1) > 0) {
				return true;
			}
		}
		return false;
	}

	public TermVector getSynonyms(String wordQuery) {
		TermVector resultado = new TermVector();

		IIndexWord idxWord = getDictionary().getIndexWord(wordQuery, POS.NOUN);
		if (idxWord == null) {
			logger.debug("Error, no se ha encontrado en el diccionario la palabra " + wordQuery);
			return resultado;
		}

		List<IWordID> words = idxWord.getWordIDs();
		// Cada una de estas parabras (IWord) tienen el mismo Lexema, pero
		// distinto significado
		for (Iterator<IWordID> iterator = words.iterator(); iterator.hasNext();) {
			IWordID wordID = iterator.next();

			IWord word = getDictionary().getWord(wordID);

			// Recuperamos el conjunto de sinonimos para el IWord
			ISynset synset = getDictionary().getSynset(word.getSynset().getID());
			// Iteramos sobre el conjunto de palabras (IWord) que son
			// sinónimos
			for (IWord sinonimo : synset.getWords()) {
				String lemaSin = sinonimo.getLemma();
				if (!lemaSin.equals(wordQuery)) {
					// agregamos el sinónimo al vector de t�rminos
					resultado.increment(lemaSin);
				}

			}
		}
		return resultado;
	}

	public String getWordMeaning(String word) {

		return null;
	}

	public String getWnhome() {
		return wnhome;
	}

	public void setWnhome(String wnhome) {
		this.wnhome = wnhome;
	}

	public IDictionary getDictionary() {
		return dictionary;
	}

	public void setDictionary(IDictionary dictionary) {
		this.dictionary = dictionary;
	}
}
